(function() {
  window.dhPlayerControl = Object.assign({
    videoWS: null,
    wsConnectCount: 0,
    wsSession: '',
    windowState: '',
    videoList: {},
    hwndList: {},
    callBackList: {},
    wsConnect: false
  }, window.dhPlayerControl || {}, {
    socketTimer: null,
    openPlayerFlag: false,
    noCardPlayerFlag: false,
    DHPlayerVersion: ''
  })
  // 在Function的原型上自定义myBind()方法
  // eslint-disable-next-line no-extend-native
  Function.prototype.myBind = function myBind(context) {
    // 获取要操作的函数
    var _this = this
    // 获取实参（context除外）
    var args = Array.prototype.slice.call(arguments, 1)

    // 判断当前浏览器是否兼容bind()方法
    if ('bind' in Function.prototype) {
      // 如果浏览器兼容bind()方法，则使用bind()方法，并返回bind()方法执行后的结果
      return _this.bind(context, args)
    }
    // 如果不兼容bind()方法，则返回一个匿名函数
    return function() {
      _this.apply(context, args)
    }
  }

  if (!document.getElementsByClassName) {
    document.getElementsByClassName = function(className, element) {
      var children = (element || document).getElementsByTagName('*')
      // eslint-disable-next-line no-array-constructor
      var elements = new Array()
      for (var i = 0; i < children.length; i++) {
        var child = children[i]
        var classNames = child.className.split(' ')
        for (var j = 0; j < classNames.length; j++) {
          if (classNames[j] === className) {
            elements.push(child)
            break
          }
        }
      }
      return elements
    }
  }

  function getWindowSize() {
    var width = window.top.innerWidth
    var height = window.top.innerHeight
    var zoom = detectZoom()
    return {
      width: width * zoom / 100,
      height: height * zoom / 100
    }
  }

  // 获取url中的参数
  function getUrlParam(url, name) {
    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)') // 构造一个含有目标参数的正则表达式对象
    var r = url.match(reg) // 匹配目标参数
    if (r != null) return unescape(r[2])
    return null // 返回参数值
  }

  // 获取页面放大缩小值
  function detectZoom() {
    var ratio = 0
    var screen = window.screen
    var ua = navigator.userAgent.toLowerCase()

    if (window.devicePixelRatio !== undefined) {
      ratio = window.devicePixelRatio
    } else if (~ua.indexOf('msie')) {
      if (screen.deviceXDPI && screen.logicalXDPI) {
        ratio = screen.deviceXDPI / screen.logicalXDPI
      }
    } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
      ratio = window.outerWidth / window.innerWidth
    }

    if (ratio) {
      ratio = Math.round(ratio * 100)
    }
    return ratio
  }
  // 进程被手动杀死或者没有主动启动时，js启动win进程
  function openDHPlayer() {
    var t = document.createElement('iframe')
    t.style.display = 'none'
    t.src = 'DHPlayer://'
    document.body.appendChild(t)
    setTimeout(function() {
      document.body.removeChild(t)
    }, 1000 * 3)
  }

  function setTimeout_close() {
    var that = this
    setTimeout(function() {
      if (!sessionStorage.getItem('HikCentralWebControlPort')) {
        window.dhPlayerControl.wsConnect = false
        window.dhPlayerControl.windowState = 'wsFail'
        window.dhPlayerControl.noCardPlayerFlag = true
        that.setting.connectClose && that.setting.connectClose()
      }
    }, that.setting.connectTime * 1000)
  }
  // socket连接
  function socketPort() {
    if (window.dhPlayerControl.noCardPlayerFlag) {
      return
    }
    if (typeof WebSocket === 'undefined') {
      alert('您的浏览器不支持socket')
      return
    }
    if (sessionStorage.getItem('HikCentralWebControlPort')) {
      sessionStorage.removeItem('HikCentralWebControlPort')
    }
    var startIp = 8000
    var endIp = 8004
    var portList = []
    var portMessage = {}
    for (var i = startIp; i <= endIp; i++) {
      portList.push(i)
    }
    var len = portList.length
    var map = {}
    var eLen = 0
    var id = 0
    var startIndex = 0
    var setTimeoutFlag = false
    window.dhPlayerControl.socketTimer && window.clearTimeout(window.dhPlayerControl.socketTimer)
    window.dhPlayerControl.windowState = 'wsPending'

    function ecallback(e) {
      window.dhPlayerControl.DHPlayerVersion = Number(e.data.ver)
      var o = sessionStorage.getItem('HikCentralWebControlPort')
      map['ws' + o].close()
      setTimeoutFlag = true
      socketOpen()
    }

    function esuccess(evt) {
      var port = evt.target.url.split(':').length === 3 ? evt.target.url.split(':')[2].replace('/', '') : '80'
      var json = {
        method: 'common.version',
        info: {},
        id,
        session: window.dhPlayerControl.wsSession
      }
      map['ws' + port] && map['ws' + port].readyState === 1 && map['ws' + port].send(JSON.stringify(json))
    }

    function eerror(evt) {
      eLen++
      var port = evt.target.url.split(':').length === 3 ? evt.target.url.split(':')[2].replace('/', '') : '80'
      map['ws' + port].close()
      if (!window.dhPlayerControl.noCardPlayerFlag) {
        startIndex = startIndex === len - 1 ? 0 : startIndex + 1
        estart()
      }
      if (eLen === len) {
        if (!window.dhPlayerControl.openPlayerFlag) {
          window.dhPlayerControl.openPlayerFlag = true
          openDHPlayer()
        }
      }
    }

    function emessage(evt) {
      var data = evt && evt.data ? JSON.parse(evt.data) : {}
      if (data.id === id) {
        window.dhPlayerControl.openPlayerFlag = true
        var port = evt.target.url.split(':').length === 3 ? evt.target.url.split(':')[2].replace('/', '') : '80'
        sessionStorage && sessionStorage.setItem('HikCentralWebControlPort', port)
        portMessage[portList[startIndex]] = 1
        ecallback(data)
      } else {
        eerror(evt)
      }
    }

    function estart() {
      map['ws' + portList[startIndex]] = new WebSocket('ws://localhost:' + portList[startIndex])
      map['ws' + portList[startIndex]].onopen = esuccess
      map['ws' + portList[startIndex]].onerror = eerror
      map['ws' + portList[startIndex]].onmessage = emessage
    }

    estart()

    // 如果端口被占用，状态不返回，主动去获取再判断
    window.dhPlayerControl.socketTimer = setTimeout(function() {
      if (!setTimeoutFlag) {
        var count = 0
        for (var i = 0; i < portList.length; i++) {
          if (portMessage[portList[startIndex]] !== 1) {
            count++
          }
          if (count === portList.length) {
            if (!window.dhPlayerControl.openPlayerFlag) {
              window.dhPlayerControl.openPlayerFlag = true
              openDHPlayer()
            }
          }
        }
      }
    }, 20 * 1000)
  }

  function socketOpen() {
    var o = sessionStorage.getItem('HikCentralWebControlPort')
    window.dhPlayerControl.videoWS = new WebSocket('ws:127.0.0.1:' + o)
    window.dhPlayerControl.videoWS.onopen = function() {
      window.dhPlayerControl.windowState = 'wsSuccess'
      // heartbeat.call(that)
      for (var key in window.dhPlayerControl.videoList) {
        var currentThis = window.dhPlayerControl.videoList[key]
        currentThis && currentThis.setting.connectSuccess()
        currentThis.create()
      }
    }
    window.dhPlayerControl.videoWS.onerror = socketOpen
    window.dhPlayerControl.videoWS.onmessage = socketMessage
  }

  // 心跳
  // eslint-disable-next-line no-unused-vars
  function heartbeat() {
    var that = this
    window.wsHeart = window.setInterval(function() {
      that.send({
        method: 'common.heartbeat',
        info: {},
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      })
    }, 30 * 1000)
  }

  function dataURLtoBlob(dataurl) {
    var mime = 'image/jpeg'
    var bstr = atob(dataurl)
    var n = bstr.length
    var u8arr = new Uint8Array(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], {
      type: mime
    })
  }
  function downloadFileByBase64(base64, name) {
    var myBlob = dataURLtoBlob(base64)
    var myUrl = URL.createObjectURL(myBlob)
    return myUrl
  }

  // 连接成功，信息返回
  function socketMessage(evt) {
    // this.setting.heartCount = 0 // 心跳计数至为0
    if (evt.data == null || evt.data === '') {
      return
    }
    var data = JSON.parse(evt.data)
    if (data.info) {
      var hwndInfo = window.dhPlayerControl.hwndList[data.info.hwnd]
      switch (data.method) {
        case 'web.seekRecord':
          hwndInfo.switchStartTime && hwndInfo.switchStartTime({
            startTime: data.info.seekTime,
            snum: data.info.snum
          })
          break
        case 'web.replay':
          hwndInfo.replay && hwndInfo.replay(data.info.snum)
          break
        case 'window.selected':
          hwndInfo.snum = data.info.snum
          hwndInfo.getCurrentWindow && hwndInfo.getCurrentWindow(data.info.snum)
          break
        case 'video.close':
          hwndInfo.snum = data.info.wndId
          hwndInfo.closeWindowSuccess && hwndInfo.closeWindowSuccess({
            isAll: data.info.isAll,
            snum: hwndInfo.snum
          })
          break
        // eslint-disable-next-line no-mixed-spaces-and-tabs
		        case 'talk.close':
          hwndInfo.snum = data.info.wndId
          hwndInfo.closeTalkSuccess && hwndInfo.closeTalkSuccess({
            isAll: data.info.isAll,
            snum: hwndInfo.snum
          })
          break
        case 'web.captureCallBack':
          var imageUrl = data.info.PicBuf ? downloadFileByBase64(data.info.PicBuf) : ''
          hwndInfo.snapshotSuccess && hwndInfo.snapshotSuccess({
            base64Url: data.info.PicBuf,
            path: imageUrl
          })
          break
        case 'window.LocalRecordFinish':
          hwndInfo.videoDownloadSuccess && hwndInfo.videoDownloadSuccess(data.info.path)
        // eslint-disable-next-line no-fallthrough
        default:
          break
      }
    }
    var onError = null
    var onSuccess = null
    if (window.dhPlayerControl.callBackList[data['id']]) {
      onError = window.dhPlayerControl.callBackList[data['id']].onError
      onSuccess = window.dhPlayerControl.callBackList[data['id']].onSuccess
    }
    if (data.code !== 0) {
      if (onError && typeof onError === 'function') {
        onError(data)
        delete window.dhPlayerControl.callBackList[data['id']]
      }
      return
    }
    // var option = this.setting.option_id[data.id]
    // if (!option) {
    //     return
    // }
    window.dhPlayerControl.wsSession = data.session
    if (onSuccess && typeof onSuccess === 'function') {
      onSuccess(data)
      delete window.dhPlayerControl.callBackList[data['id']]
    }
  }
  // socket /Oxc 选择
  function sendSocket(option, callBack) {
    // 区分IE
    if (!['window.change', 'window.shield'].includes(option.method)) {
      console.log('web', JSON.stringify(option))
    }
    window.dhPlayerControl.videoWS && window.dhPlayerControl.videoWS.readyState === 1 && window.dhPlayerControl.videoWS.send(JSON.stringify(option))
  }
  // 主动关闭socket
  function socketClose() {
    window.dhPlayerControl.videoWS && window.dhPlayerControl.videoWS.close()
    window.dhPlayerControl.videoWS = null
    window.wsHeart = clearInterval(window.wsHeart)
  }

  // 获取浏览器和对应浏览器版本
  function broswerInfo() {
    // 前置条件
    var _broswer = function() {
      // 浏览器判断和版本号读取
      var Sys = {}
      var userAgent = navigator.userAgent.toLowerCase()
      var s;
      // eslint-disable-next-line no-cond-assign
      (s = userAgent.match(/edge\/([\d.]+)/))
        ? (Sys.edge = s[1])
        // eslint-disable-next-line no-cond-assign
        : (s = userAgent.match(/rv:([\d.]+)\) like gecko/))
          ? (Sys.ie = s[1])
        // eslint-disable-next-line no-cond-assign
          : (s = userAgent.match(/msie ([\d.]+)/))
            ? (Sys.ie = s[1])
          // eslint-disable-next-line no-cond-assign
            : (s = userAgent.match(/firefox\/([\d.]+)/))
              ? (Sys.firefox = s[1])
            // eslint-disable-next-line no-cond-assign
              : (s = userAgent.match(/chrome\/([\d.]+)/))
                ? (Sys.chrome = s[1])
              // eslint-disable-next-line no-cond-assign
                : (s = userAgent.match(/opera.([\d.]+)/))
                  ? (Sys.opera = s[1])
                // eslint-disable-next-line no-cond-assign
                  : (s = userAgent.match(/version\/([\d.]+).*safari/))
                    ? (Sys.safari = s[1])
                    : 0

      if (Sys.edge) {
        return {
          broswer: 'Edge',
          version: Sys.edge
        }
      }
      if (Sys.ie) {
        return {
          broswer: 'IE',
          version: Sys.ie
        }
      }
      if (Sys.firefox) {
        return {
          broswer: 'Firefox',
          version: Sys.firefox
        }
      }
      if (Sys.chrome) {
        return {
          broswer: 'Chrome',
          version: Sys.chrome
        }
      }
      if (Sys.opera) {
        return {
          broswer: 'Opera',
          version: Sys.opera
        }
      }
      if (Sys.safari) {
        return {
          broswer: 'Safari',
          version: Sys.safari
        }
      }

      return {
        broswer: '',
        version: '0'
      }
    }
    var _version = _broswer()

    if (_version.broswer === 'IE') {
      return 0
    } else if (_version.broswer === 'Chrome') {
      return 1
    } else if (_version.broswer === 'Firefox') {
      return 2
    } else {
      return -1
    }
  }

  // 判断元素是否可见
  function isVisible(name, type = 'id') {
    if (document.visibilityState === 'hidden') {
      return false
    }
    var el = null
    if (type === 'class') {
      el = document.getElementsByClassName(name)[0]
    } else {
      el = document.getElementById(name)
    }
    if (!name || !el) {
      type === 'id' && (this.setting.visible = false)
      return false
    }
    var windowWith = document.documentElement.clientWidth
    var windowHeight = document.documentElement.clientHeight
    var rect = getRect.call(this, type === 'id' ? '' : name)
    var left = rect.left
    var top = rect.top
    var right = rect.right
    var bottom = rect.bottom
    if (top >= windowHeight || bottom <= 0 || right <= 0 || left >= windowWith) {
      type === 'id' && (this.setting.visible = false)
      return false
    }
    var loopable = true
    var visible = getComputedStyle(el).display !== 'none' && getComputedStyle(el).visibility !== 'hidden'

    while (loopable && visible) {
      el = el.parentNode
      if (el && el !== document.body) {
        visible = getComputedStyle(el).display !== 'none' && getComputedStyle(el).visibility !== 'hidden'
      } else {
        loopable = false
      }
    }
    type === 'id' && (this.setting.visible = visible)
    return visible
  }

  // 获取视频位置
  function getRect(name) {
    var el = ''
    var videoId = this.setting.videoId
    if (name) {
      el = document.getElementsByClassName(name)[0]
    } else {
      el = document.getElementById(videoId)
    }
    if (!el) {
      return {}
    }
    var rect = el.getBoundingClientRect()
    var zoom = detectZoom()
    var outLeft = 0
    var outTop = 0
    var outHeight = 0
    var outWidth = 0
    var iframes = window.parent.document.getElementsByTagName('iframe')
    var pIframe = null
    for (var i = 0; i < iframes.length; i++) {
      var dom = ''
      if (name) {
        dom = iframes[i].contentWindow.document.getElementsByClassName(name)[0]
      } else {
        dom = iframes[i].contentWindow.document.getElementById(videoId)
      }
      if (dom) {
        pIframe = iframes[i]
        break
      }
    }
    if (pIframe) {
      var pOutContent = pIframe.getBoundingClientRect()
      outLeft = pOutContent.left
      outTop = pOutContent.top
      outWidth = (this.setting.outContent.width || pOutContent.width) * zoom / 100
      outHeight = (this.setting.outContent.height || pOutContent.height) * zoom / 100
    }
    var left = rect.left + (this.setting.outContent.left || outLeft)
    var top = rect.top + (this.setting.outContent.top || outTop)
    left = left * zoom / 100
    top = top * zoom / 100
    rect.width = rect.width * zoom / 100
    rect.height = rect.height * zoom / 100
    var right = left + rect.width
    var bottom = top + rect.height
    return {
      left,
      top,
      right,
      bottom,
      outLeft: (this.setting.outContent.left || outLeft) * zoom / 100,
      outTop: (this.setting.outContent.top || outTop) * zoom / 100,
      outWidth,
      outHeight,
      width: rect.width,
      height: rect.height
    }
  }

  var VideoPlayer = function(option) {
    if (!option) {
      throw new Error('请传入配置参数')
    }
    if (this instanceof VideoPlayer) {
      var _setting = {
        isIE: !!window.ActiveXObject || 'ActiveXObject' in window, // 判断是否为IE
        videoId: 'DHVideoPlayer',
        windowType: 0, // 0-普通预览，1-普通回放（含分屏、不含时间轴），2-预览（不含分屏），3-录像回放（不含分屏、含时间轴）
        outContent: {
          left: 0,
          right: 0,
          width: 0,
          height: 0
        },
        show: true, // 当前窗口显示状态，隐藏：false，显示：true
        connectTime: 60, // 尝试连接时间，默认60s，60s后断开尝试连接
        connectSuccess: null, // 初始化成功
        connectError: null, // 初始化失败
        connectClose: null, // 关闭
        option_id: {},
        heartCount: 0, // 心跳失败计数
        refreshTimer: null,
        browserType: 1,
        isDestroy: false,
        version: 0,
        stopRefresh: false, // 停止一直刷新
        visible: false,
        showBar: true, // 是否显示下方控制栏。 true: 显示， false：隐藏
        hwnd: '', // 窗口句柄
        snum: 0, // 子窗口编号
        mount: true, // 挂载方式 true 挂载为浏览器子窗口 false 独立窗口
        num: 1 // 子窗口数
      }
      this.setting = Object.assign({}, _setting, option)
      if (_setting.isIE) {
        var dom = document.getElementById(this.setting.videoId)
        this.setting.ieDom = this.setting.videoId + '_box'
        var el = document.createElement('object')
        el.setAttribute('id', this.setting.ieDom)
        el.setAttribute('classid', 'clsid:1e68fa30-f1b5-4bbe-b483-8caaa2a3995a')
        el.style.width = '100%'
        el.style.height = '100%'
        dom.appendChild(el)
      }
      this.adjustCount = 0
      this.focus = false
      this.init()
    } else {
      return new VideoPlayer(option)
    }
  }
  VideoPlayer.fn = VideoPlayer.prototype = {
    // 浏览器关闭或者刷新
    onbeforeunload: function() {
      this.destroy()
      socketClose()
    },
    // 发送消息
    send: function(option, callBack) {
      if (callBack && Object.keys(callBack).length) {
        window.dhPlayerControl.callBackList[option['id']] = callBack
      }
      if (this.setting.isIE) {
        this.MainCall(option)
      } else {
        sendSocket.call(this, option)
      }
    },
    // 创建视频窗口
    create: function(callBack = {
      onSuccess: this.setting.createSuccess,
      onError: this.setting.createError
    }) {
      var rect = getRect.call(this)
      var _info = Object.assign({}, {}, rect)
      var windowSize = getWindowSize()
      _info.num = this.setting.num
      _info.toolBar = this.setting.showBar ? 1 : 0
      _info.windowType = this.setting.windowType
      _info.browserType = this.setting.browserType
      _info.clientAreaHeight = windowSize.height
      _info.clientAreaWidth = windowSize.width
      var that = this
      this.send({
        method: 'window.create',
        info: _info,
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      }, {
        onSuccess: function(data) {
          if (data.data && data.data.hwnd != null) {
            var hwnd = data.data.hwnd
            that.setting.hwnd = hwnd
            window.dhPlayerControl.hwndList[hwnd] = that.setting
          }
          window.addEventListener('beforeunload', that.onbeforeunload.myBind(that))
          document.addEventListener('click', that.setTop.myBind(that))
          that.handleAdjust()
          document.addEventListener('visibilitychange', that.setVisible.myBind(that), true)
          callBack.onSuccess && callBack.onSuccess(data)
        },
        onError: function() {
          // eslint-disable-next-line no-undef
          callBack.onError && callBack.onError(data)
        }
      })
    },
    setVisible() {
      if (document.visibilityState === 'hidden') {
        this.hide()
      } else {
        if (isVisible.call(this, this.setting.videoId)) {
          this.show()
        }
      }
    },
    // 页面聚焦
    setTop() {
      this.focus = true
      !this.setting.isDestroy && this.browserFocusBlur()
    },
    browserFocusBlur: function(option, callBack) {
      var _option = this.extendOption(['hwnd', 'snum', 'show'], option)
      this.send({
        method: 'browserFocusBlur',
        info: {
          hwnd: _option.hwnd,
          browserType: this.setting.browserType,
          show: this.setting.show,
          focus: this.focus
        },
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    // 刷新窗口位置
    handleAdjust: function() {
      if (this.setting.stopRefresh || this.setting.isDestroy) {
        return
      }
      var _this = this
      // 每5帧执行一次
      if (this.adjustCount % 5) {
        this.adjustCount++
      } else {
        this.adjustCount = 1
        this.changePosition()
        this.windowShield(this.cover())
      }
      this.setting.refreshTimer = window.requestAnimationFrame(function() {
        return _this.handleAdjust()
      })
    },
    // 销毁视频窗口
    destroy: function(callBack) {
      var _option = this.extendOption(['hwnd'])
      this.send({
        method: 'window.destroy',
        info: {
          hwnd: _option.hwnd,
          browserType: this.setting.browserType
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
      this.setting.isDestroy = true
      document.removeEventListener('click', this.setTop.myBind(this))
      document.removeEventListener('visibilitychange', this.setVisible.myBind(this), true)
      window.removeEventListener('beforeunload', this.onbeforeunload.myBind(this))
    },
    /**
         * @method chooseWindow 支持用户选择子窗口
         * @param { Number } snum 选择的子窗口，从0开始
         */
    chooseWindow: function(snum, callBack = {
      onSuccess: this.setting.chooseWindowSuccess,
      onError: this.setting.chooseWindowError
    }) {
      this.send({
        method: 'window.select',
        info: {
          hwnd: this.setting.hwnd,
          snum: snum
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
      this.windowShield(this.cover())
    },
    /**
         * @method realmonitor 实时预览
         * @param { Number } option.snum 选择的子窗口，从0开始
         * @param { String } option.path 预览地址
         * @param { Boolean } option.redirect 默认重定向，非重定向需用户自己传 option.redirect=false
         */
    realmonitor: function(option, callBack = {
      onSuccess: this.setting.realTimeSuccess,
      onError: this.setting.realTimeError
    }) {
      var _option = this.extendOption(['hwnd', 'snum'], option)
      var _info = {}
      _info.hwnd = _option.hwnd
      _info.snum = _option.snum
      _info.path = _option.path
      _info['browserType'] = this.setting.browserType
      _info.redirect = typeof _option.redirect === 'boolean' ? _option.redirect : true // 默认重定向，非重定向需用户自己传 option.redirect=false
      this.send({
        method: 'video.realmonitor',
        info: _info,
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
      this.windowShield(this.cover())
    },
    // eslint-disable-next-line no-mixed-spaces-and-tabs
	    /**
         * @method realmonitor 对讲
         * @param { Number } option.snum 选择的子窗口，从0开始
         * @param { String } option.path 预览地址
         */
    talk: function(option, callBack) {
      var _option = this.extendOption(['hwnd', 'snum'], option)
      _option['browserType'] = this.setting.browserType
      this.send({
        method: 'video.starttalk',
        info: _option,
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
      this.windowShield(this.cover())
    },
    /**
         * @method playback 录像回放
         * @param { Number } option.snum 选择的子窗口，从0开始
         * @param { String } option.path 回放地址
         * @param { Array } option.records 包含某个时间段的录像文件信息
         * @param { Number } option.startTime 时间相关均为时间戳,具体参考大华播放空间开发手册
         * @param { Boolean } option.redirect 默认重定向，非重定向需用户自己传 option.redirect=false
         */
    playback: function(option, callBack = {
      onSuccess: this.setting.playbackSuccess,
      onError: this.setting.playbackError
    }) {
      var _option = this.extendOption(['hwnd', 'snum'], option)
      var _info = {}
      _info.hwnd = _option.hwnd
      _info.snum = _option.snum
      _info.path = _option.path
      _info.records = _option.records
      _info.startTime = _option.startTime
      _info.endTime = _option.endTime
      _info.playStartTime = _option.playStartTime
      _info.playEndTime = _option.playEndTime
      _info.browserType = this.setting.browserType
      _info.redirect = typeof _option.redirect === 'boolean' ? _option.redirect : true
      if (_option.playStartTime) {
        var beforeStart = getUrlParam(_info.path, 'begintime')
        _info.path = _info.path.replace(beforeStart, _option.playStartTime)
      }
      this.send({
        method: 'video.playback',
        info: _info,
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
      this.windowShield(this.cover())
    },
    changePosition: function(option, callBack) {
      var _option = this.extendOption(['hwnd'], option)
      var windowSize = getWindowSize()
      var rect = getRect.call(this)
      var _info = Object.assign({}, {}, rect, _option)
      _info['browserType'] = this.setting.browserType
      _info.clientAreaHeight = windowSize.height
      _info.clientAreaWidth = windowSize.width
      _info.show = isVisible.call(this, this.setting.videoId)
      this.send({
        method: 'window.change',
        info: _info,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    // 隐藏视频
    hide: function(callBack = {
      onSuccess: this.setting.hideWindowSuccess,
      onError: this.setting.hideWindowError
    }) {
      var _option = this.extendOption(['hwnd'])
      this.setting.show = false
      this.setting.stopRefresh = true
      this.send({
        method: 'window.show',
        info: {
          hwnd: _option.hwnd,
          show: false,
          browserType: this.setting.browserType
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    // 显示视频
    show: function() {
      var that = this
      var _option = this.extendOption(['hwnd'])
      this.setting.stopRefresh = false
      this.setting.show = true
      this.send({
        method: 'window.show',
        info: {
          hwnd: _option.hwnd,
          show: true,
          browserType: this.setting.browserType
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      {
        onSuccess: function() {
          if (that.setting.refreshTimer) {
            window.cancelAnimationFrame(that.setting.refreshTimer)
          }
          that.handleAdjust()
          that.setting.showWindowSuccess && that.setting.showWindowSuccess()
        },
        onError: this.setting.showWindowError
      }
      )
    },
    /**
         * @method closeVideo 关闭指定窗口视频或全部关闭
         * @param { Number } option.snum 选择的子窗口，从0开始
         * @param { Boolean } option.isAll 是否全部关闭
         */
    closeVideo: function(option, callBack = {
      onSuccess: this.setting.closeVideoSuccess,
      onError: this.setting.closeVideoError
    }) {
      var _option = this.extendOption(['hwnd', 'snum'], option)
      this.send({
        method: 'video.close',
        info: {
          hwnd: _option.hwnd,
          snum: _option.snum,
          isAll: option.isAll
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    /**
         * @method closeTalk 关闭指定窗口对讲或全部关闭
         * @param { Number } option.snum 选择的子窗口，从0开始
         * @param { Boolean } option.isAll 是否全部关闭
         */
    closeTalk: function(option, callBack = {
      onSuccess: this.setting.closeTalkSuccess,
      onError: this.setting.closeTalkError
    }) {
      var _option = this.extendOption(['hwnd', 'snum'], option)
      this.send({
        method: 'video.closetalk',
        info: {
          hwnd: _option.hwnd,
          snum: _option.snum,
          isAll: option.isAll
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    /**
         * @method continuePlayback 操作录像
         * @param { Number } option.snum 选择的子窗口，从0开始
         * @param { Number } option.state 窗口状态：0-暂停，1-继续
         */
    controlPlayback: function(option, callBack = {
      onSuccess: this.setting.controlPlaybackSuccess,
      onError: this.setting.controlPlaybackError
    }) {
      var _option = this.extendOption(['hwnd', 'snum'], option)
      this.send({
        method: 'video.playbackChangeState',
        info: {
          hwnd: _option.hwnd,
          snum: _option.snum,
          state: option.state
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    // 显示下方控制栏, show: true-显示，false-隐藏
    showControlBar: function(show) {
      var _option = this.extendOption(['hwnd'])
      this.send({
        method: 'video.setToolBarShow',
        info: {
          hwnd: _option.hwnd,
          isShow: show ? 1 : 0,
          browserType: this.setting.browserType
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      })
    },
    /**
         * @method continuePlayback 本地录像下载
         * @param { Number } snum 选择的子窗口，从0开始
         */
    localRecordDownload: function(snum, callBack = {
      onSuccess: this.setting.recordDownloadSuccess,
      onError: this.setting.recordDownloadError
    }) {
      this.send({
        method: 'vidoe.localRecord',
        info: {
          hwnd: this.setting.hwnd,
          snum
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    // 窗口抓图
    snapshot: function(snum) {
      this.send({
        method: 'video.snapic',
        info: {
          hwnd: this.setting.hwnd,
          snum
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      })
    },
    // 视频被遮挡处理
    windowShield: function(option, callBack) {
      var _option = this.extendOption(['hwnd'], option)
      var windowSize = getWindowSize()
      var _info = {}
      _info.hwnd = _option.hwnd
      _info['browserType'] = this.setting.browserType
      _info.region = this.getShieldRect(option)
      _info['clientAreaHeight'] = windowSize.height
      _info['clientAreaWidth'] = windowSize.width
      this.send({
        method: 'window.shield',
        info: _info,
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    // 视频插件版本号
    version: function(callBack) {
      this.send({
        method: 'common.version',
        info: {},
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    getWindowState: function(callBack) {
      var _option = this.extendOption(['hwnd'])
      this.send({
        method: 'window.getWindowState',
        info: {
          hwnd: _option.hwnd
        },
        id: window.dhPlayerControl.wsConnectCount++,
        session: window.dhPlayerControl.wsSession
      },
      callBack
      )
    },
    cover: function() {
      var rect = getRect.call(this)
      var windowSize = getWindowSize()
      var left = rect.left
      var top = rect.top
      var right = rect.right
      var bottom = rect.bottom + 1
      var width = rect.width
      var height = rect.height
      var outLeft = rect.outLeft
      var outTop = rect.outTop
      var outWidth = rect.outWidth
      var outHeight = rect.outHeight
      var width_cover, height_cover, left_cover, top_cover
      var arr = []
      // 判断左边
      if (left < outLeft) {
        width_cover = outLeft - left
        arr.push(left, top, width_cover, height)
      }
      if (top < outTop) {
        height_cover = outTop - top
        arr.push(left, top, width, height_cover)
      }
      var win_width = (outWidth + outLeft) || windowSize.width
      var win_height = (outHeight + outTop) || windowSize.height
      // 判断右边
      if (win_width - right < 0) {
        // 页面太窄，显示不下视频的情况
        left_cover = win_width
        width_cover = right - left_cover
        arr.push(left_cover, top, width_cover, height)
      }

      if (win_height - bottom < 0) {
        // 页面太低，显示不下视频的情况
        height_cover = bottom - win_height
        arr.push(left, win_height, width, height_cover)
      }

      // 特殊情况 有重叠部分再传一遍
      if (win_width - right < 0 && win_height - bottom < 0) {
        // 右下
        width_cover = right - left_cover
        height_cover = bottom - win_height
        arr.push(win_width, win_height, width_cover, height_cover)
      }
      if (left < 0 && top < 0) {
        // 左上
        width_cover = Math.abs(left)
        height_cover = Math.abs(top)
        arr.push(left, top, width_cover, height_cover)
      }
      if (win_width - right < 0 && top < 0) {
        // 右上
        left_cover = win_width
        width_cover = right - left_cover
        height_cover = -top
        arr.push(left_cover, top, width_cover, height_cover)
      }
      if (left < 0 && win_height - bottom < 0) {
        // 左下
        top_cover = win_height
        width_cover = -left
        height_cover = bottom - top_cover
        arr.push(left, top_cover, width_cover, height_cover)
      }
      return arr
    },
    // copy
    extendOption: function(ids, option) {
      var map = {}
      for (var i = 0; i < ids.length; i++) {
        map[ids[i]] = this.setting[ids[i]]
      }
      return Object.assign({}, map, option)
    },
    // 遮挡部分位置获取
    getShieldRect: function(option) {
      var shieldClass = this.setting.shieldClass || []
      var rect
      var arr = option || []
      for (var i = 0; i < shieldClass.length; i++) {
        if (!isVisible.call(this, shieldClass[i], 'class')) {
          continue
        }
        rect = getRect.call(this, shieldClass[i])
        arr.push(rect.left, rect.top, rect.width, rect.height)
      }
      return arr
    },
    // 获取操作系统
    getOsInfo: function() {
      var userAgent = window.navigator.userAgent.toLowerCase()
      var version = ''
      if (userAgent.indexOf('win') > -1) {
        if (userAgent.indexOf('windows nt 5.0') > -1 || userAgent.indexOf('Windows 2000') > -1) {
          version = 'Windows 2000'
        } else if (userAgent.indexOf('windows nt 5.1') > -1 || userAgent.indexOf('Windows XP') > -1) {
          version = 'Windows XP'
        } else if (userAgent.indexOf('windows nt 5.2') > -1 || userAgent.indexOf('Windows 2003') > -1) {
          version = 'Windows 2003'
        } else if (userAgent.indexOf('windows nt 6.0') > -1 || userAgent.indexOf('Windows Vista') > -1) {
          version = 'Windows Vista'
        } else if (userAgent.indexOf('windows nt 6.1') > -1 || userAgent.indexOf('windows 7') > -1) {
          version = 'Windows 7'
        } else if (userAgent.indexOf('windows nt 6.2') > -1 || userAgent.indexOf('windows 8') > -1) {
          version = 'Windows 8'
        } else if (userAgent.indexOf('windows nt 6.3') > -1) {
          version = 'Windows 8.1'
        } else if (userAgent.indexOf('windows nt 6.4') > -1 || userAgent.indexOf('windows nt 10') > -1) {
          version = 'Windows 10'
        } else {
          version = 'Unknown'
        }
      } else if (userAgent.indexOf('iphone') > -1) {
        version = 'Iphone'
      } else if (userAgent.indexOf('mac') > -1) {
        version = 'Mac'
      } else if (
        userAgent.indexOf('x11') > -1 ||
                userAgent.indexOf('unix') > -1 ||
                userAgent.indexOf('sunname') > -1 ||
                userAgent.indexOf('bsd') > -1
      ) {
        version = 'Unix'
      } else if (userAgent.indexOf('linux') > -1) {
        if (userAgent.indexOf('android') > -1) {
          version = 'Android'
        } else {
          version = 'Linux'
        }
      } else {
        version = 'Unknown'
      }
      return version
    },
    initConnect: function() {
      // 初始化成功
      this.setting.connectSuccess()
      this.create()
    },
    MainCall: function(option) {
      var dom = document.getElementById(this.setting.ieDom)
      if (option['method'] === 'common.heartbeat') {
        this.setting.heartCount++
        if (this.setting.heartCount >= 3) {
          dom = null
          this.setting.connectClose()
          return
        }
      } else {
        this.setting.option_id[option.id] = option
      }
      dom && dom.MainCall(option.method, JSON.stringify(option))
    },
    init: function() {
      var that = this
      if (this.setting.isIE) {
        this.initConnect()
      } else {
        if (!window.dhPlayerControl.wsConnect) {
          window.dhPlayerControl.wsConnect = true
          window.dhPlayerControl.videoList[that.setting.videoId] = this
          socketPort.call(that)
          setTimeout_close.call(that)
        } else if (window.dhPlayerControl.windowState === 'wsSuccess') {
          this.setting.connectSuccess && this.setting.connectSuccess()
          that.create()
        } else {
          window.dhPlayerControl.videoList[that.setting.videoId] = this
        }
      }
      this.setting.browserType = broswerInfo()
    }
  }
  window.VideoPlayer = window.VideoPlayer || VideoPlayer
})()
